package com.xhs.miniapp.api;

import com.xhs.common.error.XhsErrorException;
import com.xhs.common.service.XhsService;
import com.xhs.common.util.http.RequestExecutor;
import com.xhs.common.util.http.RequestHttp;
import com.xhs.miniapp.api.impl.XhsMaUserService;
import com.xhs.miniapp.bean.XhsMaJscode2SessionResult;
import com.xhs.miniapp.config.XhsMaConfig;

import java.util.Map;
import java.util.function.Function;

/**
 * The interface Wx ma service.
 */
public interface XhsMaService extends XhsService {
  String XHS_HOST = "https://miniapp-sandbox.xiaohongshu.com";
  /** 获取access_token. */
  String ACCESS_TOKEN_URL = XHS_HOST+"/api/rmp/token";

  /** The constant JSCODE_TO_SESSION_URL. */
  String JSCODE_TO_SESSION_URL = XHS_HOST+"/api/rmp/session";

  /**
   * 获取登录后的session信息.
   *
   * @param jsCode 登录时获取的 code
   * @return the wx ma jscode 2 session result
   * @throws XhsErrorException the wx error exception
   */
  XhsMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws XhsErrorException;

  /**
   *
   *
   * <pre>
   * 验证消息的确来自微信服务器.
   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
   * </pre>
   *
   * @param timestamp the timestamp
   * @param nonce the nonce
   * @param signature the signature
   * @return the boolean
   */
  boolean checkSignature(String timestamp, String nonce, String signature);

  /**
   * 获取access_token, 不强制刷新access_token.
   *
   * @return the access token
   * @throws XhsErrorException the wx error exception
   * @see #getAccessToken(boolean) #getAccessToken(boolean)
   */
  String getAccessToken() throws XhsErrorException;

  /**
   *
   *
   * <pre>
   * 获取access_token，本方法线程安全.
   * 且在多线程同时刷新时只刷新一次，避免超出2000次/日的调用次数上限
   *
   * 另：本service的所有方法都会在access_token过期是调用此方法
   *
   * 程序员在非必要情况下尽量不要主动调用此方法
   *
   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
   * </pre>
   *
   * @param forceRefresh 强制刷新
   * @return the access token
   * @throws XhsErrorException the wx error exception
   */
  String getAccessToken(boolean forceRefresh) throws XhsErrorException;

  /**
   *
   *
   * <pre>
   * Service没有实现某个API的时候，可以用这个，
   * 比{@link #get}和{@link #post}方法更灵活，可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
   * 可以参考，{ MediaUploadRequestExecutor}的实现方法
   * </pre>
   *
   * @param <T> .
   * @param <E> .
   * @param executor 执行器
   * @param uri 接口请求地址
   * @param data 参数或请求数据
   * @return . t
   * @throws XhsErrorException the wx error exception
   */
  <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws XhsErrorException;

  /**
   *
   *
   * <pre>
   * 设置当微信系统响应系统繁忙时，要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
   * 默认：1000ms
   * </pre>
   *
   * @param retrySleepMillis 重试等待毫秒数
   */
  void setRetrySleepMillis(int retrySleepMillis);

  /**
   *
   *
   * <pre>
   * 设置当微信系统响应系统繁忙时，最大重试次数.
   * 默认：5次
   * </pre>
   *
   * @param maxRetryTimes 最大重试次数
   */
  void setMaxRetryTimes(int maxRetryTimes);

  /**
   * 获取WxMaConfig 对象.
   *
   * @return WxMaConfig wx ma config
   */
  XhsMaConfig getWxMaConfig();

  /**
   * 注入 {@link XhsMaConfig} 的实现.
   *
   * @param maConfig config
   */
  void setWxMaConfig(XhsMaConfig maConfig);

  /**
   * Map里 加入新的 {@link XhsMaConfig}，适用于动态添加新的微信公众号配置.
   *
   * @param miniappId 小程序标识
   * @param configStorage 新的微信配置
   */
  void addConfig(String miniappId, XhsMaConfig configStorage);

  /**
   * 从 Map中 移除 {@link String miniappId} 所对应的 {@link XhsMaConfig}，适用于动态移除小程序配置.
   *
   * @param miniappId 对应小程序的标识
   */
  void removeConfig(String miniappId);

  /**
   * 注入多个 {@link XhsMaConfig} 的实现. 并为每个 {@link XhsMaConfig} 赋予不同的 {@link String mpId} 值 随机采用一个{@link
   * String mpId}进行Http初始化操作
   *
   * @param configs WxMaConfig map
   */
  void setMultiConfigs(Map<String, XhsMaConfig> configs);

  /**
   * 注入多个 {@link XhsMaConfig} 的实现. 并为每个 {@link XhsMaConfig} 赋予不同的 {@link String label} 值
   *
   * @param configs WxMaConfig map
   * @param defaultMiniappId 设置一个{@link XhsMaConfig} 所对应的{@link String defaultMiniappId}进行Http初始化
   */
  void setMultiConfigs(Map<String, XhsMaConfig> configs, String defaultMiniappId);

  /**
   * 进行相应的公众号切换.
   *
   * @param mpId 公众号标识
   * @return 切换是否成功 boolean
   */
  boolean switchover(String mpId);

  /**
   * 进行相应的小程序切换.
   *
   * @param miniAppId 小程序标识
   * @return 切换成功 ，则返回当前对象，方便链式调用，否则抛出异常
   */
  XhsMaService switchoverTo(String miniAppId);

  /**
   * 进行相应的小程序切换.
   *
   * @param miniAppId 小程序标识
   * @param func 当对应的小程序配置不存在时，允许通过函数的方式进行调用获取
   * @return 切换成功 ，则返回当前对象，方便链式调用，否则抛出异常
   */
  XhsMaService switchoverTo(String miniAppId, Function<String, XhsMaConfig> func);

  /** 初始化http请求对象. */
  void initHttp();

  /**
   * 请求http请求相关信息.
   *
   * @return . request http
   */
  RequestHttp getRequestHttp();

  XhsMaUserService getUserService();

}
